package aimis.config;


import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.OncePerRequestFilter;
import aimis.service.UserService;

import java.io.IOException;
import java.util.Arrays;


@Configuration
@EnableWebSecurity
@EnableMethodSecurity(prePostEnabled = true)
@EnableAspectJAutoProxy
public class SecurityConfig {
    @Autowired
    private UserService userService;
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        //配置从此开始
        //http.authorizeRequests().antMatchers("/teacher/findAll").permitAll(); //login随时可以访问
        //http.authorizeRequests().antMatchers("/login").permitAll();
        //http.authorizeRequests().antMatchers("/img").permitAll(); //图像可以访问
        //http.authorizeRequests().antMatchers("/preview/**").permitAll();
        //http.authorizeRequests().antMatchers("/springfox.js","/swagger-ui/**","/images/*","/v2/api-docs","/swagger-ui.html","/webjars/**","/swagger-resources/**","/configuration/*").permitAll(); //login随时可以访问
        //http.authorizeRequests().anyRequest().authenticated(); //其他ULR的请求都需要验证
        //http.authorizeRequests().antMatchers("/api/**").authenticated(); //访问/api下的请求都需要验证
        //http.authorizeHttpRequests().requestMatchers("/login","/swagger-ui/**","/v3/**").permitAll();
        //http.authorizeHttpRequests().anyRequest().authenticated();
        http.csrf().disable(); //禁用csrf
        http.cors(); //支持跨域请求
        http.authorizeHttpRequests().requestMatchers("/user/login","/test/**","/swagger-ui/**","/v3/**","/getHostInfo","/saveSn","/getHistoryAll","/**").permitAll();
        //附件预览下载不需要权限
        http.authorizeHttpRequests().requestMatchers(HttpMethod.GET,"/attachment/**").permitAll();
        http.authorizeHttpRequests().anyRequest().authenticated();
        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);//禁用session

        http.exceptionHandling().authenticationEntryPoint(new AuthenticationEntryPoint() {
            @Override
            public void commence(HttpServletRequest request, HttpServletResponse response,
                                 AuthenticationException authException) throws IOException, ServletException {
                response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "没有凭证或凭证错误");
            }
        });
        http.addFilterBefore(new OncePerRequestFilter() {
            @Override
            protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
                                            FilterChain filterChain) throws ServletException, IOException {
                String token = request.getHeader("token");
                if (token == null)
                    token = request.getParameter("token");
                if (token != null&&!token.isBlank()) {
                    UserDetails userDetails = userService.getUserDetails(token);
                    if (userDetails != null) {
                        //把用户信息写到spring security的context里面，后面的访问就不需要用户登录了
                        UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
                                userDetails, null, userDetails.getAuthorities());
                        authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(
                                request));
                        SecurityContextHolder.getContext().setAuthentication(authentication);

                    }
                }
                filterChain.doFilter(request, response);
            }

        }, UsernamePasswordAuthenticationFilter.class);
        return http.build();
    }

    @Bean
    public CorsConfigurationSource corsConfigurationSource() {
        final CorsConfiguration configuration = new CorsConfiguration();
        //configuration.setAllowedOrigins(Arrays.asList("*"));
        configuration.addAllowedOriginPattern("*");
        configuration.setAllowedMethods(Arrays.asList("HEAD", "GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"));
        configuration.setAllowCredentials(true);
        configuration.setAllowedHeaders(Arrays.asList("Authorization", "Cache-Control", "Content-Type", "token","userId","departmentId")); //注意一定要有token，因为header里面带了token
        final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }

    @Bean
    PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder(); //密码加密方式
    }
}